package go_phpserver_client

import (
	"net"
	"fmt"
	"time"
	"encoding/json"
	"bufio"
	"git.oschina.net/solate/go-phpserver-client/utils"
	"git.oschina.net/solate/go-phpserver-client/model"
	"github.com/syndtr/goleveldb/leveldb/errors"
)

const(
	NET_READ_TIMEOUT = time.Second * 5
)



//go phpserver client
//
//
//conn net.Conn 客户端连接
//async bool 是否使用异步
//configName string 配置名称
//rpcClass string rpcClass的名称
//rpcUri string rpc uri地址
//rpcUser string rpc用户名
//rpcSecret string rpc秘钥
//rpcCompressor string rpc 版本, 暂时没有用处
type Client struct  {

	conn net.Conn
	async bool

	//不确定属性
	configName string
	rpcClass string
	rpcUri string
	rpcUser string
	rpcSecret string
	rpcCompressor string  //暂时没用不做考虑

	clientConfig *model.Config

	//replyChan chan string  //异步
	//lock sync.Mutex

}

//创建客户端
//
//name string 客户端名称, 如 "Example"
func New(config *model.Config) (c *Client, err error)   {

	//如果配置文件为空,直接返回
	if config == nil {
		return nil, errors.New("config is nil!")
	}

	c = &Client{
		clientConfig : config,
		rpcUri : config.Address.Uri,
		rpcUser : config.Address.User,
		rpcSecret : config.Address.Secret,
	}

	return
}

//
//func (c *Client) Async() *Client{
//	(*c).async = true
//
//	go c.start()
//	return c
//}

func (c *Client) Close() error {
	return c.conn.Close()
}

func(c *Client) SetClass(name string)  {

	var className string
	//ver := c.clientConfig.Address.Ver
	//if ver > 0 && ver < 2.0 {
	//	className = "RpcClient_" + c.configName + "_" + name
	//} else {
	//	className = "RpcClient_" + name
	//}

	//TODO 没找到传入是数组的模式所以暂定为都是大于2.0版本的
	className = "RpcClient_" + name

	(*c).rpcClass = className

}

//调用对应方法
//reply string 返回的是服务端json串
func(c *Client) Call(method string, args interface{}) (reply string, err error) {

	//获取连接
	err = c.connect()
	if err != nil {
		return
	}

	//数据打包
	packet,err := c.packData(method, args)
	if err != nil {
		return
	}

	//封装协议
	buffer, err := c.sendData(packet)
	if err != nil {
		return
	}

	//发送消息
	_, err = c.conn.Write([]byte(buffer))
	if err != nil {
		return
	}


	reder := bufio.NewReader(c.conn)
	//接收回复
	_, err = reder.ReadString('\n')
	if err != nil {
		return
	}

	reply, err = reder.ReadString('\n')
	if err != nil {
		return
	}

	return

}

func (c *Client) connect() error {
	conn, err := net.Dial("tcp", c.rpcUri)
	if err != nil {
		return err
	}
	(*c).conn = conn
	return nil
}

func (c *Client) sendData(packet *model.Packet) (string, error) {

	var owlContextClient map[string]string
	//TODO 如果owl_context_client 不为空, 全局变量并没看到哪里使用
	//owl_context_client := map[string]string{
	//	"app_name" : "undefined",
	//}


	owlContent, err := json.Marshal(owlContextClient)
	if err != nil {
		return "", err
	}
	context := map[string]string{
		"owl_context" : string(owlContent),
	}
	packet.Context = context

	data, err := json.Marshal(packet)
	if err != nil {
		return "", err
	}

	// 发送 RPC 文本请求协议
	command := "RPC";
	buffer := fmt.Sprintf("%d\n%s\n%d\n%s\n", len(command), command, len(string(data)), string(data));

	return buffer, nil

}



func (c *Client) packData(method string, arguments interface{}) (*model.Packet, error) {

	content := model.Content{
		Version : "2.0",
		User : c.rpcUser,
		Password : utils.GetMD5ByByte([]byte(c.rpcUser), []byte(c.rpcSecret), ':'),
		Timestamp : time.Now().Unix(),
		Class : c.rpcClass,
		Method : method,
		Params : arguments,
	}

	data, err := json.Marshal(content)
	if err != nil {
		return nil, err
	}

	packet := &model.Packet{
		Data : string(data),
	}

	//TODO 记录日志
	//trace_logger :=

	packet.Signature = c.encrypt(data, []byte(c.clientConfig.RpcSecretKey))

	return packet, nil
}

func (c *Client) encrypt(data, secret []byte) string {
	return utils.GetMD5ByByte(data, secret, '&')
}


//
////异步调用
///**
//日志启动
//开始监听并循环讲注册进来的各种日志方式进行输出
// */
//func (c *Client) start()  {
//	for  {
//		select {
//		case  <-c.replyChan:
//
//		}
//	}
//}
